package com.aiwiown.snackmq.broker.handler;

import com.aiwiown.snackmq.broker.auth.AuthorizationService;
import com.aiwiown.snackmq.cluster.metadata.MetadataManager;
import com.aiwiown.snackmq.cluster.raft.closeure.SnackMQApplyClosure;
import com.aiwiown.snackmq.common.auth.Action;
import com.aiwiown.snackmq.common.exception.AuthorizationException;
import com.aiwiown.snackmq.common.handler.MessageHandler;
import com.aiwiown.snackmq.common.handler.RequestContext;
import com.aiwiown.snackmq.common.message.Message;
import com.aiwiown.snackmq.common.message.MessageStatus;
import com.aiwiown.snackmq.common.message.MessageType;
import com.aiwiown.snackmq.common.routing.ExchangeType;
import lombok.extern.slf4j.Slf4j;

/**
 * 交换机声明处理器，用于处理声明交换机的请求。
 */
@Slf4j
public class DeclareExchangeHandler implements MessageHandler {

    /**
     * 元数据管理器，用于管理集群的元数据信息。
     */
    private final MetadataManager metadataManager;
    private final AuthorizationService authorizationService;

    /**
     * 构造函数，初始化 DeclareExchangeHandler。
     *
     * @param metadataManager 元数据管理器
     */
    public DeclareExchangeHandler(MetadataManager metadataManager, AuthorizationService authorizationService) {
        this.metadataManager = metadataManager;
        this.authorizationService = authorizationService;
    }

    /**
     * 处理声明交换机的请求。
     * 如果当前节点不是 leader，则响应失败并提供 leader 地址（如果有）。
     * 如果请求中缺少交换机名称或类型信息，则响应错误。
     * 否则，尝试声明交换机，如果声明成功则异步处理，如果失败则响应错误。
     *
     * @param ctx     请求上下文
     * @param message 消息对象，包含请求信息
     */
    @Override
    public void handle(RequestContext ctx, Message message) {
        if (!metadataManager.isLeader()) {
            // --- 【核心修复】: 使用 Builder 模式正确构建响应 ---
            String leaderAddress = metadataManager.getLeaderAddress();
            Message.MessageBuilder responseBuilder = Message.builder()
                    .messageId(message.getMessageId())
                    .type(MessageType.RESPONSE)
                    .status(MessageStatus.REDIRECT)
                    .errorMessage("Not a leader.");

            if (leaderAddress != null) {
                responseBuilder.property("redirectAddress", leaderAddress);
            }

            ctx.writeResponse(responseBuilder.build());
            return;
        }

        try {
            final String exchangeName = message.getProperty("exchangeName");
            final String exchangeTypeStr = message.getProperty("exchangeType");
            // 【修复】授权检查：声明交换机是集群级管理操作，需要对 CLUSTER 资源有 MANAGE 权限
            authorizationService.authorize(message.getProperty("authToken"), Action.MANAGE, new AuthorizationService.Resource("CLUSTER", "*"));

            if (exchangeName == null || exchangeName.isEmpty() || exchangeTypeStr == null) {
                String errorMsg = "Declare exchange request must contain non-empty exchangeName and exchangeType properties.";
                log.warn(errorMsg);
                SnackMQApplyClosure.sendErrorResponse(ctx, message, errorMsg);
                return;
            }

            final ExchangeType type = ExchangeType.valueOf(exchangeTypeStr.toUpperCase());
            log.debug("Proposing DECLARE_EXCHANGE: exchange='{}', type='{}'", exchangeName, type);
            this.metadataManager.declareExchange(
                    exchangeName,
                    type,
                    new SnackMQApplyClosure(message, ctx, null)
            );
        } catch (AuthorizationException e) {
            log.warn("Authorization failed for declare exchange request: {}", e.getMessage());
            ctx.writeResponse(Message.builder().messageId(message.getMessageId()).status(MessageStatus.FAILED).errorMessage("Permission denied: " + e.getMessage()).build());
        } catch (IllegalArgumentException e) {
            log.warn("Invalid exchangeType in DECLARE_EXCHANGE request: {}", message.getProperty("exchangeType"), e);
            SnackMQApplyClosure.sendErrorResponse(ctx, message, "Invalid exchangeType: " + message.getProperty("exchangeType"));
        } catch (Exception e) {
            log.error("Failed to process DECLARE_EXCHANGE request", e);
            SnackMQApplyClosure.sendErrorResponse(ctx, message, "Internal server error: " + e.getMessage());
        }
    }

    /**
     * 获取处理的消息类型。
     *
     * @return 消息类型为 DECLARE_EXCHANGE_REQUEST
     */
    @Override
    public MessageType getMessageType() {
        return MessageType.DECLARE_EXCHANGE_REQUEST;
    }
}
